﻿namespace OpenAdmin.Application.Services;

/// <summary>
/// 租户服务
/// </summary>
public class TenantService : ServiceBase, ITenantService, ITransientDependency
{
    private readonly IRepository<EFCoreTenant, MultiTenancyDbContextLocator> _tenantRepository;
    private readonly IRepository<SysUser, ApplicationDbContextLocator> _userRepository;
    private readonly IRepository<SysRole, ApplicationDbContextLocator> _roleRepository;
    private readonly IRepository<SysUserRole, ApplicationDbContextLocator> _userRoleRepository;
    /// <summary>
    /// 
    /// </summary>
    /// <param name="tenantRepository"></param>
    /// <param name="userRepository"></param>
    /// <param name="roleRepository"></param>
    /// <param name="userRoleRepository"></param>
    public TenantService(IRepository<EFCoreTenant, MultiTenancyDbContextLocator> tenantRepository,
        IRepository<SysUser, ApplicationDbContextLocator> userRepository,
        IRepository<SysRole, ApplicationDbContextLocator> roleRepository,
        IRepository<SysUserRole, ApplicationDbContextLocator> userRoleRepository)
    {
        _tenantRepository = tenantRepository;
        _userRepository = userRepository;
        _roleRepository = roleRepository;
        _userRoleRepository = userRoleRepository;
    }

    /// <summary>
    /// 分页获取租户信息
    /// </summary>
    /// <param name="requestDto"></param>
    /// <returns></returns>
    public async Task<PagedList<TenantsByPageResponseDto>> GetTenantsByPage(TenantsByPageRequestDto requestDto)
    {
        var queryableTenant = _tenantRepository.Entities.AsQueryable();
        if (!string.IsNullOrWhiteSpace(requestDto.Keyworld))
        {
            queryableTenant = queryableTenant.Where(p => p.Name.Contains(requestDto.Keyworld));
        }
        var dtos = await queryableTenant.ProjectToType<TenantsByPageResponseDto>()
            .ToPagedListAsync(p => p.CreatedTime, requestDto.PageIndex, requestDto.PageSize);

        return dtos;
    }
    /// <summary>
    /// 添加租户
    /// </summary>
    /// <param name="requestDto"></param>
    /// <returns></returns>
    public async Task AddTenant(AddTenantRequestDto requestDto)
    {
        var tenant = await _tenantRepository.Entities.FirstOrDefaultAsync(p => p.Name == requestDto.Name);
        tenant.ThrowIf(p => p != null, "租户名已存在");

        tenant = await _tenantRepository.Entities.FirstOrDefaultAsync(p => p.Email == requestDto.Email);
        tenant.ThrowIf(p => p != null, "邮箱(账号)已存在");

        tenant = requestDto.Adapt<EFCoreTenant>();

        using (var transaction = _tenantRepository.Database.BeginTransaction())
        {
            try
            {
                var tenantEntry = await _tenantRepository.InsertAndCommitEntryAsync(tenant);
                using (var transaction2 = _userRepository.Database.BeginTransaction())
                {
                    try
                    {
                        var result = await InitTenantData(tenantEntry.Entity);
                        if (result)
                        {
                            await transaction.CommitAsync();
                            await transaction2.CommitAsync();
                        }
                    }
                    catch { throw; }
                }
            }
            catch { throw; }
        }
    }

    /// <summary>
    /// 更新租户信息
    /// </summary>
    /// <param name="requestDto"></param>
    public async Task EditTenant(EditTenantRequestDto requestDto)
    {
        var tenant = await _tenantRepository.Entities.FirstOrDefaultAsync(p => p.TenantId == requestDto.TenantId);
        tenant.ThrowIf(p => p == null, "租户不存在");

        var anyTenant = await _tenantRepository.Entities.FirstOrDefaultAsync(p => p.TenantId != requestDto.TenantId && p.Name == requestDto.Name);
        anyTenant.ThrowIf(p => p != null, "租户名已存在");

        anyTenant = await _tenantRepository.Entities.FirstOrDefaultAsync(p => p.TenantId != requestDto.TenantId && p.Email == requestDto.Email);
        anyTenant.ThrowIf(p => p != null, "邮箱(账号)已存在");

        tenant.Name = requestDto.Name;
        tenant.Email = requestDto.Email;
        tenant.PhoneNumber = requestDto.PhoneNumber;
        tenant.Enabled = requestDto.Enabled;
        tenant.Remark = requestDto.Remark;

        await _tenantRepository.UpdateAndCommitAsync(tenant);
    }

    /// <summary>
    /// 删除租户
    /// </summary>
    /// <param name="tenantId"></param>
    public async Task DeleteTenant(string tenantId)
    {
        Guid.TryParse(tenantId, out var intTenantId);
        var tenant = await _tenantRepository.Entities.FirstOrDefaultAsync(p => p.TenantId == intTenantId);
        tenant.ThrowIf(p => p == null, "租户不存在");

        var users = await _userRepository.Entities.IgnoreQueryFilters().Where(p => p.TenantId == intTenantId).ToListAsync();
        var roles = await _roleRepository.Entities.IgnoreQueryFilters().Where(p => p.TenantId == intTenantId).ToListAsync();
        var userIds = users.Select(p => p.Id).ToList();
        var roleIds = roles.Select(p => p.Id).ToList();
        var userRoles = await _userRoleRepository.Entities.Where(p => roleIds.Contains(p.RoleId) || userIds.Contains(p.UserId)).ToListAsync();

        using (var transaction = _tenantRepository.Database.BeginTransaction())
        {
            try
            {
                await _tenantRepository.DeleteAndCommitAsync(tenant);

                using (var transaction2 = _userRepository.Database.BeginTransaction())
                {
                    try
                    {
                        await _userRepository.DeleteAndCommitAsync(users);
                        await _roleRepository.DeleteAndCommitAsync(roles);
                        await _userRoleRepository.DeleteAndCommitAsync(userRoles);

                        await transaction.CommitAsync();
                        await transaction2.CommitAsync();
                    }
                    catch { throw; }
                }
            }
            catch { throw; }
        }
    }

    private async Task<bool> InitTenantData(EFCoreTenant tenant)
    {
        var userEntry = await _userRepository.InsertAndCommitEntryAsync(new SysUser
        {
            TenantId = tenant.TenantId,
            RealName = tenant.Name,
            UserName = tenant.Email,
            Password = MD5Encryption.MD5Encrypt32("123456"),
            UserType = UserType.SystemAdmin,
            Status = 1,
            Gender = 1,
            Age = 18,
            Birthday = DateTime.Now.AddYears(-18),
        });

        var roleEntry = await _roleRepository.InsertAndCommitEntryAsync(new SysRole
        {
            TenantId = tenant.TenantId,
            Name = "系统管理员",
            Enabled = true,
            Remark = "系统管理员",
        });

        var userRoleEntry = await _userRoleRepository.InsertAndCommitEntryAsync(new SysUserRole
        {
            UserId = userEntry.Entity.Id,
            RoleId = roleEntry.Entity.Id,
        });

        return userEntry.Entity.Id > 0 && roleEntry.Entity.Id > 0 && userRoleEntry.Entity.RoleId > 0;
    }

}
